#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "LogMessage.hpp"
#include "protocol.hpp"
#include <functional>
#include <sys/wait.h>

using namespace std;
#define DEFAULT_IP "0.0.0.0"
#define RECV_MAX_BUFF 4096

typedef function<void(http_request &, http_response &)> Fun;

class http_server
{
public:
    http_server(uint32_t port, Fun fun)
        : _port(port), _ip(DEFAULT_IP), _monitor_skfd(-1), _fun(fun) {}

    ~http_server() {}

    void server_init()
    {
        // 创建套接字
        _monitor_skfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_monitor_skfd < 0)
        {
            logMessage(ERROR, "create monitor socket error");
            exit(0);
        }

        // bind port
        struct sockaddr_in server;
        server.sin_family = AF_INET;
        server.sin_port = htons(_port);
        server.sin_addr.s_addr = inet_addr(_ip.c_str());
        socklen_t len = sizeof(server);

        int check = bind(_monitor_skfd, (struct sockaddr *)&server, len);
        if (check == -1)
        {
            logMessage(ERROR, "bind socket error");
            exit(0);
        }
        else
            logMessage(NORMAL, "bind socket success");

        // 设置监听套接字
        check = listen(_monitor_skfd, 5);
        if (check == -1)
        {
            logMessage(ERROR, "set listen socket error");
            exit(0);
        }
        else
            logMessage(NORMAL, "set listen socket success");
    }

    void hand_http(int sockfd)
    {

        http_request req;
        http_response resp;

        // 1. 读到完整的http请求
        char buff[RECV_MAX_BUFF] = {0};

        ssize_t size = recv(sockfd, buff, sizeof buff - 1, 0);
        if (size > 0)
        {
            cout << buff << endl;

            // 2. 反序列化
            req._inbuff = buff;
            req.parse();
        }

        // 3. httprequst, httpresponse, _func(req, resp)
        _fun(req, resp);

        // 4. resp序列化

        // 5. send
        send(sockfd, resp._outbuff.c_str(), resp._outbuff.size(), 0);
    }

    void server_start()
    {
        while (true)
        {
            struct sockaddr_in client;
            socklen_t len = sizeof client;
            int sockfd = accept(_monitor_skfd, (struct sockaddr *)&client, &len);
            if (sockfd < 0)
            {
                logMessage(ERROR, "accept client error");
                continue;
            }
            else
                logMessage(NORMAL, "accept client success");

            pid_t id = fork();
            if (id == 0)
            {
                close(_monitor_skfd);
                if (fork() > 0)
                    exit(0);
                hand_http(sockfd);
                close(sockfd);
                exit(0);
            }

            close(sockfd);
            waitpid(id, nullptr, 0);
        }
    }

private:
    string _ip;
    uint16_t _port;
    int _monitor_skfd;
    Fun _fun;
};